package com.origin.app.page.map

import android.graphics.Color
import androidx.databinding.ObservableInt
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.amap.api.maps.AMap
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.LatLngBounds
import com.amap.api.maps.model.Polygon
import com.amap.api.maps.model.PolygonOptions
import com.google.gson.GsonBuilder
import com.origin.app.bean.BaseNetBean
import com.origin.app.bean.CompanyBean
import com.origin.app.bean.CompanyPointBean
import com.origin.app.bean.NavRefreshBean
import com.origin.app.bean.NotOnLineRepBean
import com.origin.app.bean.NotOnLineReqBean
import com.origin.app.bean.PointNetInfoBean
import com.origin.app.bean.PolygonBean
import com.origin.app.utils.AppUtils
import com.origin.app.utils.MapUtils
import com.origin.app.utils.NetAppUtils
import com.origin.app.utils.UserInfoUtils
import com.origin.app.utils.dialog.DialogUtils
import com.origin.baselibrary.viewmodel.BaseViewModel
import com.origin.utils.gson.GsonUtils
import com.origin.utils.log.LogUtils
import ikidou.reflect.TypeBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.withContext


class AppMapViewModel : BaseViewModel() {
    val selectIndex = ObservableInt(0)
    val refreshListMutableLiveData = MutableLiveData<Long>()

    var navList = mutableListOf<CompanyPointBean>()


    fun getTaskIdByPolygon(companyPointBean: CompanyPointBean, aMap: AMap) {
        if(polygonList.size>0){
            polygonList.forEach {
                it.remove()
            }
            polygonList.clear()
            return
        }
        DialogUtils.showLoadDialog("加载中...")
        viewModelSuspend {
            val type = TypeBuilder.newInstance(BaseNetBean::class.java)
                .beginSubType(List::class.java)
                .addTypeParam(PolygonBean::class.java)
                .endSubType()
                .build()
            var netBean = NetAppUtils.get<BaseNetBean<List<PolygonBean>>>(
                NetAppUtils.getTaskIdByPolygonUrl + "/${companyPointBean.taskId}",
                type,
                this
            );
            if (netBean.isOk) {
                LogUtils.__e("getTaskIdByPolygon 长度 " + netBean.data.size)
                val polygonPointList = mutableListOf<LatLng>()

                for (datum in netBean.data) {
                    val str = datum.polygon_pointstr.removeSuffix(";")
                    val strArray = str.split(";")
                    for (s in strArray) {
                        val latLngStr = s.split(",")
                        if (latLngStr.size == 2) {
                            try {
                                val latLng =
                                    LatLng(latLngStr[1].toDouble(), latLngStr[0].toDouble())
                                polygonPointList.add(latLng)
                            } catch (e: Exception) {

                            }
                        }
                    }

                    val polygonOptions = PolygonOptions()

                    LogUtils.__e("经纬度  ${polygonPointList.toString()}")
// 添加 多边形的每个顶点（顺序添加）
                    polygonOptions.addAll(polygonPointList)
                    polygonOptions.strokeWidth(15f) // 多边形的边框
                        .strokeColor(Color.parseColor(if(datum.isType){"#ff0000"}else{"#007AFF"})) // 边框颜色
                        .fillColor(if(datum.isType){Color.argb(80, 255, 0, 0)}else{Color.argb(80, 0, 122, 255)});
                    val myPolygon=  aMap.addPolygon(polygonOptions)
                    calculateCenter(polygonPointList, aMap)
                    polygonList.add(myPolygon)
                }


            }

            DialogUtils.closeLoadDialog()
        }
    }

    val polygonList= mutableListOf<Polygon>()

    private fun calculateCenter(points: List<LatLng>, aMap: AMap) {
        val builder = LatLngBounds.Builder()
        for (point in points) {
            builder.include(point);
        }
        val bounds = builder.build()
        val padding = 100 // 增加一些边缘间距
        aMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, padding));
    }

    fun getCompanyListUrl() {
        DialogUtils.showLoadDialog("加载中...")
        viewModelSuspend {
            val type = TypeBuilder.newInstance(BaseNetBean::class.java)
                .beginSubType(List::class.java)
                .addTypeParam(CompanyBean::class.java)
                .endSubType()
                .build()
            var netBean = NetAppUtils.get<BaseNetBean<List<CompanyBean>>>(
                NetAppUtils.getCompanyListUrl + "?company_code=${UserInfoUtils.getUserInfo().company_code}",
                type,
                this
            );
            if (netBean.isOk) {
                // 936
                LogUtils.__e("长度 " + netBean.data.size)
                if (netBean.data.size == 0) {
                    return@viewModelSuspend;
                }
                splitMap(netBean.data)
                LogUtils.__e("关闭进度弹窗")
            }
            refreshListMutableLiveData.postValue(System.currentTimeMillis())
            DialogUtils.closeLoadDialog()
        }
    }

    // 分级用的
    var map = mutableMapOf<Int, MutableList<CompanyBean>>()
    var companyBeanList = mutableListOf<CompanyBean>();
    var companyCodeList = mutableListOf<String>()


    private fun getTopLevel(level: Int): Int {
        if (map.containsKey(level)) {
            return level;
        }
        var nextLevel = level + 1;
        return getTopLevel(nextLevel)
    }

    private suspend fun splitMap(list: List<CompanyBean>) {
        for (companyBean in list) {
            if (map.containsKey(companyBean.level)) {
                map[companyBean.level]?.add(companyBean)
            } else {
                map[companyBean.level] = mutableListOf(companyBean)
            }
        }
        // 重新排序

        var topLevel = getTopLevel(1)
        companyBeanList.clear();
        map[topLevel]?.forEach {
            companyCodeList.add(it.company_code)
            it.tag += "${it.parent_id},"
            companyBeanList.add(it)
            it.nextSize = (findNextLevel(it, it.parent_id.toString()));
        }
        LogUtils.__e("关闭进度弹窗 1, size:  ${companyBeanList.size}")
        withContext(Dispatchers.Main) {
            getCompanyPoint()
        }
    }

    fun checkCompanyPoint() {
        DialogUtils.showLoadDialog("加载中...")
        viewModelSuspend {
            withContext(Dispatchers.IO) {
                companyCodeList.clear()
                companyBeanList.forEach {
                    if (it.isSelect) {
                        companyCodeList.add(it.company_code)
                    }
                }
                getCompanyPoint()
            }
            refreshListMutableLiveData.postValue(System.currentTimeMillis())
            DialogUtils.closeLoadDialog()
        }
    }

    var companyPointList = mutableListOf<CompanyPointBean>();


    var normalLength = ObservableInt(0);
    var exceptionLength = ObservableInt(0);
    var offlineLength = ObservableInt(0);
    var notOnlineLength = ObservableInt(0);
    var selectLength = ObservableInt(0);


    // 正常列表 1
    var normalList = mutableListOf<CompanyPointBean>();

    // 异常列表 2
    var exceptionList = mutableListOf<CompanyPointBean>();

    // 离线列表 3
    var offlineList = mutableListOf<CompanyPointBean>();

    // 未上线列表 4
    var notOnlineList = mutableListOf<CompanyPointBean>();

    fun refreshNum() {
        normalLength.set(normalList.size)
        exceptionLength.set(exceptionList.size)
        offlineLength.set(offlineList.size)
        notOnlineLength.set(notOnlineList.size)
        selectLength.set(companyCodeList.size)
    }

    private suspend fun getCompanyPoint() {
        return withContext(Dispatchers.Default) {
            val type1 = TypeBuilder.newInstance(BaseNetBean::class.java)
                .beginSubType(List::class.java)
                .addTypeParam(CompanyPointBean::class.java)
                .endSubType()
                .build()
            val map1 = mapOf("type" to 1, "company_code" to companyCodeList.joinToString("#"))
            val prettyJson1 = GsonBuilder().setPrettyPrinting().create().toJson(map1)
            var job1 = GlobalScope.async {
                NetAppUtils.privatePostJsonStr<BaseNetBean<List<CompanyPointBean>>>(
                    NetAppUtils.getPointUrl,
                    prettyJson1,
                    type1,
                    viewModelScope
                );
            }

            val notOnLineReqBean = NotOnLineReqBean()
            notOnLineReqBean.pageindex = 0;
            notOnLineReqBean.pagesize = 0;
            val whereBean = NotOnLineReqBean.WhereBean()
            notOnLineReqBean.where = whereBean
            whereBean.state = NotOnLineReqBean.WhereBean.StateBean().apply { this.`$eq` = 1 };
            val or = mutableListOf<NotOnLineReqBean.OrBean>();
            companyCodeList.forEach {
                var code = it;
                var orBean = NotOnLineReqBean.OrBean().apply {
                    where = NotOnLineReqBean.OrBean.WhereBeanX().apply {
                        company_code = NotOnLineReqBean.OrBean.WhereBeanX.CompanyCodeBean().apply {
                            this.`$eq` = code
                        }
                    }
                }
                or.add(orBean)

            }
            notOnLineReqBean.or = or

            val prettyJson2 = GsonUtils.gson.toJson(notOnLineReqBean)
            val type2 = TypeBuilder.newInstance(BaseNetBean::class.java)
                .addTypeParam(NotOnLineRepBean::class.java)
                .build()
            var job2 = GlobalScope.async {
                NetAppUtils.privatePostJsonStr<BaseNetBean<NotOnLineRepBean>>(
                    NetAppUtils.getNotOnlineUrl,
                    prettyJson2,
                    type2,
                    viewModelScope
                );
            }
            val netBean = job1.await();
            val netNotOnLineBean = job2.await();
            normalList.clear()
            exceptionList.clear()
            offlineList.clear()
            notOnlineList.clear()
            netBean.data.forEach {
                when (it.equipmentState) {
                    1 -> normalList.add(it)
                    2 -> exceptionList.add(it)
                    3 -> offlineList.add(it)
                }
            }

            companyPointList.clear()
            companyPointList.addAll(netBean.data)
            netNotOnLineBean.data.list.forEach { allBean ->
                var isAdd = true;
                netBean.data.forEach tag@{
                    if (it.in_Code == allBean.in_Code) {
                        isAdd = false
                        return@tag
                    }
                }
                if (isAdd) {
                    allBean.equipmentState = 4
                    notOnlineList.add(allBean)
                }

            }


        }

    }


    private fun findNextLevel(companyBean: CompanyBean, parentId: String): Int {
        var size = 0;
        var nextLevel = companyBean.level + 1;
        if (!map.containsKey(nextLevel)) {
            return size;
        }
        var lastSize = 0
        map[nextLevel]?.forEach {
            if (it.parent_id == companyBean.id) {
                size++;
                it.tag = parentId + "," + it.parent_id
                companyCodeList.add(it.company_code)
                companyBeanList.add(it)
                companyBean.addCompanyBean(it)
                it.nextSize = findNextLevel(it, it.tag)
                lastSize += it.nextSize;
            }
        }
        return size + lastSize;
    }

    private var allPendingDataCompanyPointBeanList = mutableListOf<CompanyPointBean>()
    fun imRefreshMarkerList(companyPointBean: CompanyPointBean) {
        allPendingDataCompanyPointBeanList.add(companyPointBean)
        viewModelSuspend {
            imRefreshMarkerListAction();
        }
    }

    val refreshListMutableSharedFlow = MutableSharedFlow<Long>()
    private suspend fun imRefreshMarkerListAction() {
        if (allPendingDataCompanyPointBeanList.size == 0) {
            return;
        }
        val companyPointBean = allPendingDataCompanyPointBeanList.removeLast()
        val state: Int = withContext(Dispatchers.IO) {
            // 检查在哪个列表中
            val normalIndex = moveItemToList(normalList, companyPointBean, 1)
            if (normalIndex < 0) {
                return@withContext normalIndex
            }
            val exceptionIndex = moveItemToList(exceptionList, companyPointBean, 2)
            if (exceptionIndex < 0) {
                return@withContext normalIndex
            }
            val offlineIndex = moveItemToList(offlineList, companyPointBean, 3)
            if (offlineIndex < 0) {
                return@withContext normalIndex
            }
            val notOnlineIndex = moveItemToList(notOnlineList, companyPointBean, 4)
            if (notOnlineIndex < 0) {
                return@withContext normalIndex
            }
            return@withContext -1;
        }
        if (state > 0) {
            // 刷新数量
            refreshListMutableSharedFlow.emit(System.currentTimeMillis())
        }
    }

    private fun moveItemToList(
        olderList: MutableList<CompanyPointBean>,
        companyPointBean: CompanyPointBean, listType: Int
    ): Int {
        val index: Int = olderList.indexOf(companyPointBean)
        if (index == -1) {
            return index;
        }
        val bean = olderList[index]

        if (bean.checkInfoSame(companyPointBean)) {
            return -2;
        }

        val newList = when (companyPointBean.equipmentState) {
            1 -> {
                normalList
            }

            2 -> {
                exceptionList
            }

            3 -> {
                offlineList
            }

            else -> {
                LogUtils.__e("异常类型 ${companyPointBean.equipmentState}")
                throw Exception("异常类型 ${companyPointBean.equipmentState}")
            }
        }
//        LogUtils.__e("从 类型 $listType 列表 移动到  类型 ${companyPointBean.equipmentState} 列表")
        val beanPre = olderList.removeAt(index)
        val mapMarkerBean = MapUtils.getCompanyPointBeanByCode(companyPointBean.in_Code)

//        LogUtils.__e("map信息 预加载 ${companyPointBean.company_Name} ,  纬度 ：${companyPointBean.gcJ02.lat} , 经度 ： ${companyPointBean.gcJ02.lng}")

        if (mapMarkerBean != null) {
            val bean = mapMarkerBean.`object`;

            if (bean is CompanyPointBean) {
                bean.refresh(companyPointBean)
                mapMarkerBean.position = LatLng(bean.gcJ02.lat, bean.gcJ02.lng)
                mapMarkerBean.setIcon(AppUtils.getPointInfoAvatar(bean.equipmentState, bean.isCard))
                if (bean.equipmentState != 1 && bean.equipmentState != 2 && bean.equipmentState != 3) {
                    mapMarkerBean.isVisible = false
                } else {
                    mapMarkerBean.isVisible = true
                }
//                MapUtils.switchEquipmentStateMarkerMap(beforeState,afterState, mapMarkerBean)
//                LogUtils.__e("map信息 前 ${bean.company_Name} ,  纬度 ：${bean.gcJ02.lat} , 经度 ： ${bean.gcJ02.lng}")
            }
        }
        beanPre.refresh(companyPointBean)
        newList.add(beanPre)

        return index;
    }


    private var pendingDataCompanyPointBeanList = mutableListOf<CompanyPointBean>()

    fun imRefreshNavList(companyPointBean: CompanyPointBean) {
        pendingDataCompanyPointBeanList.add(companyPointBean)

        viewModelSuspend {
            imRefreshNavListAction();
        }

    }


    val refreshNavListMutableLiveData = MutableSharedFlow<NavRefreshBean>()
    private suspend fun imRefreshNavListAction() {
        if (pendingDataCompanyPointBeanList.size == 0) {
            return;
        }
        val companyPointBean = pendingDataCompanyPointBeanList.removeLast()
        withContext(Dispatchers.IO) {
            val index = navList.indexOf(companyPointBean)
            if (index == -1) {
                return@withContext
            }
            val bean = navList[index]
            LogUtils.__e("imRefreshNavList 名称===>  ${bean.company_Name}  ,  netName ${companyPointBean.company_Name}")
            navList.add(0, bean)
            navList.removeAt(index + 1)
//            refreshNavListMutableLiveData.postValue(NavRefreshBean(index))
            LogUtils.__e("发送消息===》${bean.company_Name} ")
            refreshNavListMutableLiveData.emit(NavRefreshBean(index))
        }
        imRefreshNavListAction()
    }

    fun resetNavList() {
        navList.clear()
        var index = selectIndex.get()
        if (index == 1) {
            navList.addAll(normalList)
            return
        }
        if (index == 2) {
            navList.addAll(exceptionList)
            return
        }
        if (index == 3) {
            navList.addAll(offlineList)
            return
        }
        navList.addAll(normalList)
        navList.addAll(exceptionList)
        navList.addAll(offlineList)
    }

    fun resetNavNotOnlineList() {
        navList.clear()
        navList.addAll(notOnlineList)
    }

    val refreshNetPointInfoMutableLiveData = MutableLiveData<PointNetInfoBean.ListBean>()
    fun getNetPointInfo(companyPointBean: CompanyPointBean) {
        val jsonString: String =
            "{\"pageindex\":1,\"pagesize\":1,\"where\":{\"in_code\":{\"\$eq\":\"${companyPointBean.in_Code}\"},\"company_code\":{\"\$eq\":\"${companyPointBean.company_code}\"}}}"
        val type1 = TypeBuilder.newInstance(BaseNetBean::class.java)
            .addTypeParam(PointNetInfoBean::class.java)
            .build()
        viewModelSuspend {
            val bean = NetAppUtils.privatePostJsonStr<BaseNetBean<PointNetInfoBean>>(
                NetAppUtils.getPageListUrl,
                jsonString,
                type1,
                viewModelScope
            );
            if (bean.isOk) {
                var list = bean.data.list;
                if (list.size >= 1) {
                    refreshNetPointInfoMutableLiveData.postValue(list[0])
                }
            }
        }

    }
}